use serde::{Deserialize, Serialize};
use std::path::PathBuf;

const DEFAULT_SERVER_PORT: u16 = 7000;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub server: ServerConfig,
    pub database: DatabaseConfig,
    pub dvc: DvcConfig,
    pub auth: AuthConfig,
    pub cors: CorsConfig,
    pub logging: LoggingConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
    pub debug: bool,
    pub reload: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
    pub url: String,
    pub echo: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DvcConfig {
    pub storage_path: String,
    pub remote_name: String,

    pub max_file_size: usize,
    pub allowed_extensions: Vec<String>,
    pub remote_server: DvcRemoteServerConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DvcRemoteServerConfig {
    pub enabled: bool,
    pub auth: DvcAuthConfig,
    pub ssl_verify: bool,
    pub read_timeout: u64,
    pub connect_timeout: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DvcAuthConfig {
    pub enabled: bool,
    pub method: String,
    pub database_auth: DvcDatabaseAuthConfig,
    pub basic_auth: DvcBasicAuthConfig,
    pub custom_auth: DvcCustomAuthConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DvcDatabaseAuthConfig {
    pub require_admin: bool,
    pub allowed_users: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DvcBasicAuthConfig {
    pub username: String,
    pub password: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DvcCustomAuthConfig {
    pub header_name: String,
    pub token: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthConfig {
    pub jwt_secret_key: String,
    pub jwt_algorithm: String,
    pub jwt_expiration_minutes: u64,
    pub password_min_length: usize,
    pub email_suffix_regex: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CorsConfig {
    pub allowed_origins: Vec<String>,
    pub allowed_methods: Vec<String>,
    pub allowed_headers: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    pub level: String,
    pub format: String,
    pub file: Option<String>,
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            server: ServerConfig {
                host: "0.0.0.0".to_string(),
                port: DEFAULT_SERVER_PORT,
                debug: true,
                reload: true,
            },
            database: DatabaseConfig {
                url: "sqlite:///rint_data_manager.db".to_string(),
                echo: false,
            },
            dvc: DvcConfig {
                storage_path: "/opt/dvc_storage".to_string(),
                remote_name: "local_storage".to_string(),

                max_file_size: 104857600, // 100MB
                allowed_extensions: vec![
                    ".csv".to_string(),
                    ".json".to_string(),
                    ".txt".to_string(),
                    ".xlsx".to_string(),
                    ".parquet".to_string(),
                    ".h5".to_string(),
                    ".pkl".to_string(),
                    ".py".to_string(),
                    ".ipynb".to_string(),
                ],
                remote_server: DvcRemoteServerConfig {
                    enabled: false,
                    auth: DvcAuthConfig {
                        enabled: true,
                        method: "database".to_string(),
                        database_auth: DvcDatabaseAuthConfig {
                            require_admin: false,
                            allowed_users: vec![],
                        },
                        basic_auth: DvcBasicAuthConfig {
                            username: "dvc_user".to_string(),
                            password: "dvc_password".to_string(),
                        },
                        custom_auth: DvcCustomAuthConfig {
                            header_name: "X-DVC-Token".to_string(),
                            token: "your-custom-token-here".to_string(),
                        },
                    },
                    ssl_verify: true,
                    read_timeout: 300,
                    connect_timeout: 300,
                },
            },
            auth: AuthConfig {
                jwt_secret_key: "your-secret-key-here-change-in-production".to_string(),
                jwt_algorithm: "HS256".to_string(),
                jwt_expiration_minutes: 1440, // 24 hours
                password_min_length: 8,
                email_suffix_regex: ".*@hillstonenet\\.com$|.*@Hillstonenet\\.com$".to_string(),
            },
            cors: CorsConfig {
                allowed_origins: vec![
                    "http://localhost:8000".to_string(),
                    "http://127.0.0.1:8000".to_string(),
                ],
                allowed_methods: vec![
                    "GET".to_string(),
                    "POST".to_string(),
                    "PUT".to_string(),
                    "DELETE".to_string(),
                    "OPTIONS".to_string(),
                ],
                allowed_headers: vec!["*".to_string()],
            },
            logging: LoggingConfig {
                level: "INFO".to_string(),
                format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s".to_string(),
                file: Some("./logs/app.log".to_string()),
            },
        }
    }
}

impl AppConfig {
    pub fn from_env() -> anyhow::Result<Self> {
        // Try to load from config file first
        let config_path = PathBuf::from("config.yml");
        let mut config = if config_path.exists() {
            let config_content = std::fs::read_to_string(config_path)?;
            serde_yaml::from_str(&config_content)?
        } else {
            Self::default()
        };

        // Override with environment variables if they exist
        if let Ok(host) = std::env::var("RINT_SERVER_HOST") {
            config.server.host = host;
        }
        if let Ok(port_str) = std::env::var("RINT_SERVER_PORT") {
            config.server.port = port_str.parse().unwrap_or(DEFAULT_SERVER_PORT);
        }
        if let Ok(jwt_secret) = std::env::var("RINT_AUTH_JWT_SECRET_KEY") {
            config.auth.jwt_secret_key = jwt_secret;
        }

        Ok(config)
    }

    pub fn get_dvc_storage_path(&self) -> &str {
        &self.dvc.storage_path
    }

    pub fn get_dvc_remote_url(&self) -> String {
        format!("http://{}:{}/dvc", self.server.host, self.server.port)
    }
}
